﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

#region old
//namespace LCARSLibrary
//{
//    public class SetPageDependentControlDataEventArgs<T> : EventArgs where T : Control, new()
//    {
//        public T Control { get; set; }
//        public int Index { get; set; }
//    }

//    public class ControlEventArgs<T> : EventArgs where T : Control, new()
//    {
//        public T Control { get; set; }
//    }

//    public class PageChangedEventArgs : EventArgs
//    {
//        public int CurrentPage { get; set; }
//        public bool PreviousPageAvailable { get; set; }
//        public bool NextPageAvailable { get; set; }
//    }

//    public class Paging<T> : IDisposable where T : Control, new()
//    {
//        List<T> controls;

//        bool visible;
//        object tag;

//        public object Tag
//        {
//            get
//            {
//                return tag;
//            }
//            set
//            {
//                tag = value;

//                foreach (var item in controls)
//                    item.Tag = tag;
//            }
//        }

//        public bool Visible { get { return visible; } }

//        public int EntryCount { get; set; }
//        public int CurrentPage { get; set; }

//        public Control Parent { get; set; }

//        public Point StartTopLeftPosition { get; set; }
//        public Point EndBottomRightPosition { get; set; }

//        public Size ControlSize { get; set; }


//        public event EventHandler<SetPageDependentControlDataEventArgs<T>> SetPageDependentControlData;
//        public event EventHandler<PageChangedEventArgs> PageChanged;
//        public event EventHandler<ControlEventArgs<T>> InitializeControl;
//        public event EventHandler VisibleChanged;

//        protected virtual void OnSetPageDependentControlData(object sender, SetPageDependentControlDataEventArgs<T> e)
//        {
//            EventHandler<SetPageDependentControlDataEventArgs<T>> temp = SetPageDependentControlData;
//            if (temp != null)
//            {
//                temp(sender, e);
//            }
//        }

//        protected virtual void OnPageChanged(object sender, PageChangedEventArgs e)
//        {
//            EventHandler<PageChangedEventArgs> temp = PageChanged;
//            if (temp != null)
//            {
//                temp(sender, e);
//            }
//        }

//        protected virtual void OnInitializeControl(object sender, ControlEventArgs<T> e)
//        {
//            EventHandler<ControlEventArgs<T>> temp = InitializeControl;
//            if (temp != null)
//            {
//                temp(sender, e);
//            }
//        }

//        protected virtual void OnVisibleChanged(object sender, EventArgs e)
//        {
//            EventHandler temp = VisibleChanged;
//            if (temp != null)
//            {
//                temp(sender, e);
//            }
//        }


//        public Paging()
//        {
//            controls = new List<T>();
//            visible = false;
//        }

//        public bool InitializeControls()
//        {
//            if (this.Parent == null || StartTopLeftPosition == EndBottomRightPosition || ControlSize.Width == 0 || ControlSize.Height == 0)
//                return false;

//            Point currentPoint = StartTopLeftPosition;
//            int x = 0;
//            int y = 0;

//            do
//            {
//                do
//                {
//                    T control = new T();
//                    OnInitializeControl(this, new ControlEventArgs<T>() { Control = control });

//                    control.Size = ControlSize;
//                    control.Location = currentPoint;
//                    control.Tag = this.Tag;
//                    control.Hide();
//                    Parent.Controls.Add(control);
//                    controls.Add(control);
//                    control.BringToFront();

//                    y++;
//                    currentPoint.Y = StartTopLeftPosition.Y + y * ControlSize.Height;
//                }
//                while ((currentPoint.Y + ControlSize.Height) <= EndBottomRightPosition.Y);

//                x++;
//                currentPoint.X = StartTopLeftPosition.X + x * ControlSize.Width;
//            }
//            while ((currentPoint.X + ControlSize.Width) <= EndBottomRightPosition.X);

//            return true;
//        }

//        public void Show()
//        {
//            if (visible)
//                return;

//            visible = true;
//            OnVisibleChanged(this, EventArgs.Empty);
//            GoToPage(0);
//        }

//        public void Hide()
//        {
//            if (!visible)
//                return;

//            foreach (var item in controls)
//                item.Hide();

//            visible = false;
//            OnVisibleChanged(this, EventArgs.Empty);
//            OnPageChanged(this, new PageChangedEventArgs() { NextPageAvailable = false, PreviousPageAvailable = false, CurrentPage = -1 });
//        }

//        public bool GoToPage(int page)
//        {
//            if (page < 0)
//                return false;

//            if (!visible)
//                return false;

//            if (controls.Count == 0)
//                return false;

//            if (EntryCount < 1)
//            {
//                this.CurrentPage = 0;
//                OnPageChanged(this, new PageChangedEventArgs() { NextPageAvailable = false, PreviousPageAvailable = false, CurrentPage = this.CurrentPage });
//                return false;
//            }


//            bool previousPageExists = true;
//            bool nextPageExists = true;
//            bool emptyPage = false;

//            if (page == 0)
//                previousPageExists = false;

//            int entryIndex = 0;

//            for (int controlIndex = 0; controlIndex < controls.Count; controlIndex++)
//            {
//                entryIndex = controlIndex + (page * controls.Count);
//                if (EntryCount > entryIndex)
//                {
//                    //event
//                    OnSetPageDependentControlData(this, new SetPageDependentControlDataEventArgs<T>() { Control = controls[controlIndex], Index = entryIndex });
//                    controls[controlIndex].Show();
//                }
//                else
//                {
//                    if (controlIndex == 0)
//                    {
//                        emptyPage = true;

//                        if (page == 1)
//                        {
//                            //only one page exists
//                            previousPageExists = false;
//                        }

//                        //page would be empty
//                        nextPageExists = false;
//                        break;
//                    }

//                    controls[controlIndex].Hide();
//                    nextPageExists = false;
//                }
//            }

//            if (EntryCount == (entryIndex + 1)) //the current page is completely filled and therefore the last page
//                nextPageExists = false;

//            if (!emptyPage)
//                this.CurrentPage = page;

//            OnPageChanged(this, new PageChangedEventArgs() { NextPageAvailable = nextPageExists, PreviousPageAvailable = previousPageExists, CurrentPage = this.CurrentPage });

//            return true;
//        }


//        #region IDisposable Members

//        public void Dispose()
//        {
//            foreach (var item in controls)
//                item.Dispose();

//            controls.Clear();
//        }

//        #endregion
//    }
//}
#endregion


namespace LCARSLibrary
{
    public class PagingIDBased<TControl, TData> : Paging<TControl, TData>
        where TControl : Control, new()
        where TData : class, IPagingIDBasedData
    {
        public TData GetEntryByID(int id)
        {
            var d = from x in this.Data
                    where x.ID == id
                    select x;

            if (d.Count() == 0)
                return null;
            else if (d.Count() == 1)
                return d.First();
            else
                throw new Exception("Redundant ID's found!");
        }
    }

    public class Paging<TControl, TData> : IDisposable
        where TControl : Control, new()
    {
        #region fields

        bool visible;

        List<TData> data;
        List<TControl> controls;

        #endregion

        #region properties

        public Control Parent { get; set; }

        public virtual List<TData> Data
        {
            get { return data; }
            set { data = value; GoToPage(0); }
        }

        public bool Visible { get { return visible; } }

        public int CurrentPage { get; set; }

        public Point StartTopLeftPosition { get; set; }
        public Point EndBottomRightPosition { get; set; }

        public Size Spacing { get; set; }
        public Size ControlSize { get; set; }

        #endregion

        #region events

        public event EventHandler<SetPageDependentControlDataEventArgs<TControl, TData>> SetPageDependentControlData;
        public event EventHandler<PageChangedEventArgs> PageChanged;
        public event EventHandler<ControlEventArgs<TControl>> InitializeControl;
        public event EventHandler VisibleChanged;

        protected virtual void OnSetPageDependentControlData(object sender, SetPageDependentControlDataEventArgs<TControl, TData> e)
        {
            EventHandler<SetPageDependentControlDataEventArgs<TControl, TData>> temp = SetPageDependentControlData;
            if (temp != null)
            {
                temp(sender, e);
            }
        }

        protected virtual void OnPageChanged(object sender, PageChangedEventArgs e)
        {
            EventHandler<PageChangedEventArgs> temp = PageChanged;
            if (temp != null)
            {
                temp(sender, e);
            }
        }

        protected virtual void OnInitializeControl(object sender, ControlEventArgs<TControl> e)
        {
            EventHandler<ControlEventArgs<TControl>> temp = InitializeControl;
            if (temp != null)
            {
                temp(sender, e);
            }
        }

        protected virtual void OnVisibleChanged(object sender, EventArgs e)
        {
            EventHandler temp = VisibleChanged;
            if (temp != null)
            {
                temp(sender, e);
            }
        }

        #endregion


        public Paging()
        {
            controls = new List<TControl>();
            visible = false;
        }

        public bool InitializeControls()
        {
            if (this.Parent == null
                || StartTopLeftPosition == EndBottomRightPosition
                || ControlSize.IsEmpty)
                return false;

            Point currentPoint = StartTopLeftPosition;
            int x = 0;
            int y = 0;

            do
            {
                y = 0;
                currentPoint.Y = StartTopLeftPosition.Y + y * (ControlSize.Height + Spacing.Height);

                do
                {

                    TControl control = new TControl();
                    OnInitializeControl(this, new ControlEventArgs<TControl>() { Control = control });

                    control.Size = ControlSize;
                    control.Location = currentPoint;
                    control.Hide();
                    Parent.Controls.Add(control);
                    controls.Add(control);
                    control.BringToFront();

                    y++;
                    currentPoint.Y = StartTopLeftPosition.Y + y * (ControlSize.Height + Spacing.Height);
                }
                while ((currentPoint.Y + ControlSize.Height) <= EndBottomRightPosition.Y);

                x++;
                currentPoint.X = StartTopLeftPosition.X + x * (ControlSize.Width + Spacing.Width);
            }
            while ((currentPoint.X + ControlSize.Width) <= EndBottomRightPosition.X);


            return true;
        }

        public void Show()
        {
            if (visible)
                return;

            visible = true;
            OnVisibleChanged(this, EventArgs.Empty);
            GoToPage(0);
        }

        public void Hide()
        {
            if (!visible)
                return;

            foreach (var item in controls)
                item.Hide();

            visible = false;
            OnVisibleChanged(this, EventArgs.Empty);
            OnPageChanged(this, new PageChangedEventArgs() { NextPageAvailable = false, PreviousPageAvailable = false, CurrentPage = -1 });
        }

        public bool GoToPage(int page)
        {
            if (page < 0)
                return false;

            if (!visible)
                return false;

            if (controls.Count == 0)
                return false;

            if (Data.Count < 1)
            {
                this.CurrentPage = 0;
                OnPageChanged(this, new PageChangedEventArgs() { NextPageAvailable = false, PreviousPageAvailable = false, CurrentPage = this.CurrentPage });
                return false;
            }


            bool previousPageExists = true;
            bool nextPageExists = true;
            bool emptyPage = false;

            if (page == 0)
                previousPageExists = false;

            int dataEntryIndex = 0;

            for (int controlIndex = 0; controlIndex < controls.Count; controlIndex++)
            {
                dataEntryIndex = controlIndex + (page * controls.Count);
                if (Data.Count > dataEntryIndex)
                {
                    //event
                    OnSetPageDependentControlData(this, new SetPageDependentControlDataEventArgs<TControl, TData>() { Control = controls[controlIndex], Data = Data[dataEntryIndex] });
                    controls[controlIndex].Show();
                }
                else
                {
                    if (controlIndex == 0)
                    {
                        emptyPage = true;

                        if (page == 1)
                        {
                            //only one page exists
                            previousPageExists = false;
                        }

                        //page would be empty
                        nextPageExists = false;
                        break;
                    }

                    controls[controlIndex].Hide();
                    nextPageExists = false;
                }
            }

            if (Data.Count == (dataEntryIndex + 1)) //the current page is completely filled and therefore it is the last page
                nextPageExists = false;

            if (!emptyPage)
                this.CurrentPage = page;

            OnPageChanged(this, new PageChangedEventArgs() { NextPageAvailable = nextPageExists, PreviousPageAvailable = previousPageExists, CurrentPage = this.CurrentPage });

            return true;
        }

        public bool GoToLastPage()
        {
            double dResult = (double)((double)data.Count / (double)controls.Count);
            int iResult = (int)dResult;

            if (dResult != iResult)
                iResult++;

            int lastPage = iResult - 1;
            return GoToPage(lastPage);
        }

        #region IDisposable Members

        public void Dispose()
        {
            foreach (var item in controls)
                item.Dispose();

            controls.Clear();
        }

        #endregion
    }
}
